package uem.din.aeg.trab2.grafo;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class Grafo {

    private List<Vertice> vertices;
    // informações para os vértices sorteados
    private Vertice acidente;
    private Vertice hospital;
    private Vertice ambulanciaA;
    private Vertice ambulanciaB;
    private Vertice ambulanciaC;
    private Vertice ambulanciaMaisProxima;
    private static final int tamanhoMinimo = 5;

    public List<Vertice> getVertices() {
        return vertices;
    }

    public void setVertices(List<Vertice> vertices) {
        this.vertices = vertices;
    }

    public Grafo() {
        vertices = new ArrayList<Vertice>();
    }

    public Vertice getAcidente() {
        return acidente;
    }

    public Vertice getAmbulanciaA() {
        return ambulanciaA;
    }

    public Vertice getAmbulanciaB() {
        return ambulanciaB;
    }

    public Vertice getAmbulanciaC() {
        return ambulanciaC;
    }

    public Vertice getHospital() {
        return hospital;
    }

    public Vertice obtemVertice(int posicao) {
        return vertices.get(posicao);
    }

    public void adicionaVertice(Vertice v) {
        vertices.add(v);
    }

    public void sorteiaVertices() throws Exception {
        if (vertices.size() < tamanhoMinimo) {
            throw new Exception("O grafo possui menos de 5 vértices, que é o tamanho mínimo.");
        }

        Collections.shuffle(vertices);

        acidente = vertices.get(0);
        ambulanciaA = vertices.get(1);
        ambulanciaB = vertices.get(2);
        ambulanciaC = vertices.get(3);
        hospital = vertices.get(4);
    }

    /**
     * @caminho minimo Calcula o caminho do acidente para todos os vertices
     * usando o algoritmo de Dijkstra
     */
    public void caminhoMinimo() {
        List<Vertice> abertos = new ArrayList<Vertice>(this.getVertices());


        for (Vertice v : this.getVertices()) {
            v.setDistanciaEstimada(Double.POSITIVE_INFINITY);
            v.setPrecedente(null);
        }
        this.acidente.setDistanciaEstimada(0.0);

        while (!abertos.isEmpty()) {
            Collections.sort(abertos);
            Vertice u = abertos.get(0);

            abertos.remove(0);
            for (Vertice v : u.getAdjacentes()) {
                if (abertos.contains(v)) {
                    if (u.getDistanciaEstimada() + u.distanciaAte(v) < v.getDistanciaEstimada()) {
                        v.setDistanciaEstimada(u.getDistanciaEstimada() + u.distanciaAte(v));
                        v.setPrecedente(u);
                    }
                }
            }// fim do for

        }// fim do while
    }

    public String ambulanciaMaisProxima() {
        StringBuilder sb = new StringBuilder();

        if (this.ambulanciaA.getDistanciaEstimada() < this.ambulanciaB.getDistanciaEstimada()) {
            this.ambulanciaMaisProxima = this.ambulanciaA;
        } else {
            this.ambulanciaMaisProxima = this.ambulanciaB;
        }

        if (this.ambulanciaC.getDistanciaEstimada() < this.ambulanciaMaisProxima.getDistanciaEstimada()) {
            this.ambulanciaMaisProxima = ambulanciaC;
        }


        // verificar qual das ambulancias tem a distancia estimada menor
        sb.append("Ambulância mais próxima ao acidente: ");
        if (ambulanciaA.getDistanciaEstimada() == ambulanciaMaisProxima.getDistanciaEstimada()) {
            sb.append("ambulância A\n");
        } else if (ambulanciaB.getDistanciaEstimada() == ambulanciaMaisProxima.getDistanciaEstimada()) {
            sb.append("ambulância B\n");
        } else if (ambulanciaC.getDistanciaEstimada() == ambulanciaMaisProxima.getDistanciaEstimada()) {
            sb.append("ambulância C\n");
        }

        return sb.toString();
    }

    public String renderizaVerticesSorteados() {
        StringBuilder sb = new StringBuilder();

        sb.append("Acidente: ").append(acidente).append("\n");
        sb.append("Hospital: ").append(hospital).append("\n");
        sb.append("Ambulância A: ").append(ambulanciaA).append("\n");
        sb.append("Ambulância B: ").append(ambulanciaB).append("\n");
        sb.append("Ambulância C: ").append(ambulanciaC).append("\n\n");

        return sb.toString();
    }

    public String renderizaCaminhoAmbulanciaAcidente() {
        StringBuilder sb = new StringBuilder();

        sb.append("Caminho Ambulância - Acidente:\n");
        
        List<Vertice> caminhoAmbulanciaAcidente = new ArrayList<Vertice>();
        Vertice aux = this.ambulanciaMaisProxima;
        
        while (aux.getPrecedente() != null) {// Somente a origem/acidente tem precendente null
            caminhoAmbulanciaAcidente.add(aux);
            caminhoAmbulanciaAcidente.add(aux.getPrecedente());
            aux = aux.getPrecedente();
        }

        for (int i = 0; i < caminhoAmbulanciaAcidente.size(); i += 2) {
            sb.append(caminhoAmbulanciaAcidente.get(i)).append(" --> ").append(caminhoAmbulanciaAcidente.get(i + 1)).append("\n");
        }
        
        sb.append("\n");

        return sb.toString();
    }

    public String renderizaCaminhoAcidenteHospital() {
        StringBuilder sb = new StringBuilder();

        sb.append("Caminho Acidente - Hospital:\n");
        
        List<Vertice> caminhoAcidenteHospital = new ArrayList<Vertice>();
        Vertice aux = hospital;
        
        while (aux.getPrecedente() != null) {// Somente a origem/acidente tem precendente null
            caminhoAcidenteHospital.add(aux);
            caminhoAcidenteHospital.add(aux.getPrecedente());
            aux = aux.getPrecedente();
        }
        
        Collections.reverse(caminhoAcidenteHospital);
        
        for (int i = 0; i < caminhoAcidenteHospital.size(); i += 2) {
            sb.append(caminhoAcidenteHospital.get(i)).append(" --> ").append(caminhoAcidenteHospital.get(i + 1)).append("\n");
        }

        return sb.toString();
    }
}
